home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / rdist-6.1 / rdist-6 / rdist-6.1.0-linuxpl2 / src / expand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-14  |  12.2 KB  |  609 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char RCSid[] = 
  36. "$Id: expand.c,v 6.17 1994/03/14 23:25:24 mcooper Exp $";
  37.  
  38. static char sccsid[] = "@(#)expand.c    5.2 (Berkeley) 3/28/86";
  39.  
  40. char copyright[] =
  41. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  42.  All rights reserved.\n";
  43. #endif /* not lint */
  44.  
  45. #include "defs.h"
  46.  
  47. #define    MAXEARGS    2048
  48. #define LC         '{'
  49. #define RC         '}'
  50.  
  51. static char    shchars[] = "${[*?";
  52.  
  53. int        which;        /* bit mask of types to expand */
  54. int        eargc;        /* expanded arg count */
  55. char          **eargv;        /* expanded arg vectors */
  56. char           *path;
  57. char           *pathp;
  58. char           *lastpathp;
  59. char           *tilde;        /* "~user" if not expanding tilde, else "" */
  60. char           *tpathp;
  61.  
  62. int        expany;        /* any expansions done? */
  63. char           *entp;
  64. char          **sortbase;
  65. char            *argvbuf[MAXEARGS];
  66.  
  67. static int    argcmp();
  68. void        expstr();
  69. void        expsh();
  70. void        matchdir();
  71.  
  72. #define sort()    qsort((char *)sortbase, &eargv[eargc] - sortbase, \
  73.               sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
  74.  
  75. static void Cat(s1, s2)                /* quote in s1 and s2 */
  76.     register u_char *s1, *s2;
  77. {
  78.     register char *cp;
  79.     int len = strlen((char *)s1) + strlen((char *)s2) + 2;
  80.  
  81.     if ((eargc + 1) >= MAXEARGS) {
  82.         yyerror("Too many names");
  83.         return;
  84.     }
  85.  
  86.     eargv[++eargc] = (char *) NULL;
  87.     eargv[eargc - 1] = cp = xmalloc(len);
  88.  
  89.     do { 
  90.         if (*s1 == QUOTECHAR) 
  91.             s1++; 
  92.     } while (*cp++ = *s1++);
  93.     cp--;
  94.     do { 
  95.         if (*s2 == QUOTECHAR) 
  96.             s2++; 
  97.     } while (*cp++ = *s2++);
  98. }
  99.  
  100. static void addpath(c)
  101.     char c;
  102. {
  103.     if (pathp >= lastpathp) {
  104.         yyerror("Pathname too long");
  105.         return;
  106.     } else {
  107.         *pathp++ = c;
  108.         *pathp = CNULL;
  109.     }
  110. }
  111.  
  112. /*
  113.  * Take a list of names and expand any macros, etc.
  114.  * wh = E_VARS if expanding variables.
  115.  * wh = E_SHELL if expanding shell characters.
  116.  * wh = E_TILDE if expanding `~'.
  117.  * or any of these or'ed together.
  118.  *
  119.  * Major portions of this were snarfed from csh/sh.glob.c.
  120.  */
  121. struct namelist *
  122. expand(list, wh)                /* quote in list->n_name */
  123.     struct namelist *list;
  124.     int wh;
  125. {
  126.     register struct namelist *nl, *prev;
  127.     register int n;
  128.     char pathbuf[BUFSIZ];
  129.  
  130.     if (debug)
  131.         debugmsg(DM_CALL, "expand(%x, %d) start, list = %s", 
  132.              list, wh, getnlstr(list));
  133.  
  134.     if (wh == 0)
  135.         fatalerr("expand() contains invalid 'wh' argument.");
  136.  
  137.     which = wh;
  138.     path = tpathp = pathp = pathbuf;
  139.     *pathp = CNULL;
  140.     lastpathp = &path[sizeof pathbuf - 2];
  141.     tilde = "";
  142.     eargc = 0;
  143.     eargv = sortbase = argvbuf;
  144.     *eargv = (char *) NULL;
  145.  
  146.     /*
  147.      * Walk the name list and expand names into eargv[];
  148.      */
  149.     for (nl = list; nl != NULL; nl = nl->n_next)
  150.         expstr((u_char *)nl->n_name);
  151.     /*
  152.      * Take expanded list of names from eargv[] and build a new list.
  153.      */
  154.     list = prev = NULL;
  155.     for (n = 0; n < eargc; n++) {
  156.         nl = makenl((char *)NULL);
  157.         nl->n_name = eargv[n];
  158.         if (prev == NULL)
  159.             list = prev = nl;
  160.         else {
  161.             prev->n_next = nl;
  162.             prev = nl;
  163.         }
  164.     }
  165.  
  166.     return(list);
  167. }
  168.  
  169. /*
  170.  * xstrchr() is a version of strchr() that
  171.  * handles u_char buffers.
  172.  */
  173. u_char *xstrchr(str, ch)
  174.     u_char *str;
  175.     int ch;
  176. {
  177.     register u_char *cp;
  178.  
  179.     for (cp = str; cp && *cp != CNULL; ++cp)
  180.         if (ch == *cp)
  181.             return(cp);
  182.  
  183.     return((u_char *)NULL);
  184. }
  185.  
  186. void expstr(s)
  187.     u_char *s;
  188. {
  189.     register u_char *cp, *cp1;
  190.     register struct namelist *tp;
  191.     u_char *tail;
  192.     u_char ebuf[BUFSIZ];
  193.     u_char varbuff[BUFSIZ];
  194.     int savec, oeargc;
  195.     extern char *homedir;
  196.  
  197.     if (s == NULL || *s == CNULL)
  198.         return;
  199.  
  200.     /*
  201.      * Remove quoted characters
  202.      */
  203.     if (IS_ON(which, E_VARS)) {
  204.         if ((int)strlen((char *)s) > sizeof(varbuff)) {
  205.             yyerror("Variable is too large.");
  206.             return;
  207.         }
  208.         for (cp = s, cp1 = varbuff; cp && *cp; ++cp) {
  209.             /* 
  210.              * remove quoted character if the next
  211.              * character is not $
  212.              */
  213.             if (*cp == QUOTECHAR && *(cp+1) != '$')
  214.                 ++cp;
  215.             else
  216.                 *cp1++ = *cp;
  217.         }
  218.         *cp1 = CNULL;
  219.         s = varbuff;
  220.     }
  221.  
  222.     /*
  223.      * Consider string 's' a variable that should be expanded if
  224.      * there is a '$' in 's' that is not quoted.
  225.      */
  226.     if (IS_ON(which, E_VARS) && 
  227.         ((cp = xstrchr(s, '$')) && !(cp > s && *(cp-1) == QUOTECHAR))) {
  228.         *cp++ = CNULL;
  229.         if (*cp == CNULL) {
  230.             yyerror("no variable name after '$'");
  231.             return;
  232.         }
  233.         if (*cp == LC) {
  234.             cp++;
  235.             for (cp1 = cp; ; cp1 = tail + 1) {
  236.                 if ((tail = xstrchr(cp1, RC)) == NULL) {
  237.                     yyerror("unmatched '{'");
  238.                     return;
  239.                 }
  240.                 if (tail[-1] != QUOTECHAR) break;
  241.             }
  242.             *tail++ = savec = CNULL;
  243.             if (*cp == CNULL) {
  244.                 yyerror("no variable name after '$'");
  245.                 return;
  246.             }
  247.         } else {
  248.             tail = cp + 1;
  249.             savec = *tail;
  250.             *tail = CNULL;
  251.         }
  252.         tp = lookup((char *)cp, LOOKUP, (struct namelist *)NULL);
  253.         if (savec != CNULL)
  254.             *tail = savec;
  255.         if (tp != NULL) {
  256.             for (; tp != NULL; tp = tp->n_next) {
  257.                 (void) sprintf((char *)ebuf, 
  258.                            "%s%s%s", s, tp->n_name, tail);
  259.                 expstr(ebuf);
  260.             }
  261.             return;
  262.         }
  263.         (void) sprintf((char *)ebuf, "%s%s", s, tail);
  264.         expstr(ebuf);
  265.         return;
  266.     }
  267.     if ((which & ~E_VARS) == 0 || !strcmp((char *)s, "{") || 
  268.         !strcmp((char *)s, "{}")) {
  269.         Cat(s, (u_char *)"");
  270.         sort();
  271.         return;
  272.     }
  273.     if (*s == '~') {
  274.         cp = ++s;
  275.         if (*cp == CNULL || *cp == '/') {
  276.             tilde = "~";
  277.             cp1 = (u_char *)homedir;
  278.         } else {
  279.             tilde = (char *)(cp1 = ebuf);
  280.             *cp1++ = '~';
  281.             do
  282.                 *cp1++ = *cp++;
  283.             while (*cp && *cp != '/');
  284.             *cp1 = CNULL;
  285.             if (pw == NULL || strcmp(pw->pw_name, 
  286.                          (char *)ebuf+1) != 0) {
  287.                 if ((pw = getpwnam((char *)ebuf+1)) == NULL) {
  288.                     strcat((char *)ebuf, 
  289.                            ": unknown user name");
  290.                     yyerror((char *)ebuf+1);
  291.                     return;
  292.                 }
  293.             }
  294.             cp1 = (u_char *)pw->pw_dir;
  295.             s = cp;
  296.         }
  297.         for (cp = (u_char *)path; *cp++ = *cp1++; )
  298.             ;
  299.         tpathp = pathp = (char *)cp - 1;
  300.     } else {
  301.         tpathp = pathp = path;
  302.         tilde = "";
  303.     }
  304.     *pathp = CNULL;
  305.     if (!(which & E_SHELL)) {
  306.         if (which & E_TILDE)
  307.             Cat((u_char *)path, s);
  308.         else
  309.             Cat((u_char *)tilde, s);
  310.         sort();
  311.         return;
  312.     }
  313.     oeargc = eargc;
  314.     expany = 0;
  315.     expsh(s);
  316.     if (eargc == oeargc)
  317.         Cat(s, (u_char *)"");        /* "nonomatch" is set */
  318.     sort();
  319. }
  320.  
  321. static
  322. argcmp(a1, a2)
  323.     char **a1, **a2;
  324. {
  325.  
  326.     return (strcmp(*a1, *a2));
  327. }
  328.  
  329. /*
  330.  * If there are any Shell meta characters in the name,
  331.  * expand into a list, after searching directory
  332.  */
  333. void expsh(s)                /* quote in s */
  334.     u_char *s;
  335. {
  336.     register u_char *cp, *oldcp;
  337.     register char *spathp;
  338.     struct stat stb;
  339.  
  340.     spathp = pathp;
  341.     cp = s;
  342.     while (!any(*cp, shchars)) {
  343.         if (*cp == CNULL) {
  344.             if (!expany || stat(path, &stb) >= 0) {
  345.                 if (which & E_TILDE)
  346.                     Cat((u_char *)path, (u_char *)"");
  347.                 else
  348.                     Cat((u_char *)tilde, (u_char *)tpathp);
  349.             }
  350.             goto endit;
  351.         }
  352.         if (*cp == QUOTECHAR) cp++;
  353.         addpath(*cp++);
  354.     }
  355.     oldcp = cp;
  356.     while (cp > s && *cp != '/')
  357.         cp--, pathp--;
  358.     if (*cp == '/')
  359.         cp++, pathp++;
  360.     *pathp = CNULL;
  361.     if (*oldcp == '{') {
  362.         (void) execbrc(cp, (u_char *)NULL);
  363.         return;
  364.     }
  365.     matchdir((char *)cp);
  366. endit:
  367.     pathp = spathp;
  368.     *pathp = CNULL;
  369. }
  370.  
  371. void matchdir(pattern)                /* quote in pattern */
  372.     char *pattern;
  373. {
  374.     struct stat stb;
  375.     register DIRENTRY *dp;
  376.     DIR *dirp;
  377.  
  378.     dirp = opendir(path);
  379.     if (dirp == NULL) {
  380.         if (expany)
  381.             return;
  382.         goto patherr2;
  383.     }
  384.     if (fstat(dirp->dd_fd, &stb) < 0)
  385.         goto patherr1;
  386.     if (!S_ISDIR(stb.st_mode)) {
  387.         errno = ENOTDIR;
  388.         goto patherr1;
  389.     }
  390.     while ((dp = readdir(dirp)) != NULL)
  391.         if (match(dp->d_name, pattern)) {
  392.             if (which & E_TILDE)
  393.                 Cat((u_char *)path, (u_char *)dp->d_name);
  394.             else {
  395.                 (void) strcpy(pathp, dp->d_name);
  396.                 Cat((u_char *)tilde, (u_char *)tpathp);
  397.                 *pathp = CNULL;
  398.             }
  399.         }
  400.     closedir(dirp);
  401.     return;
  402.  
  403. patherr1:
  404.     closedir(dirp);
  405. patherr2:
  406.     (void) strcat(path, ": ");
  407.     (void) strcat(path, SYSERR);
  408.     yyerror(path);
  409. }
  410.  
  411. execbrc(p, s)                /* quote in p */
  412.     u_char *p, *s;
  413. {
  414.     u_char restbuf[BUFSIZ + 2];
  415.     register u_char *pe, *pm, *pl;
  416.     int brclev = 0;
  417.     u_char *lm, savec;
  418.     char *spathp;
  419.  
  420.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  421.         if (*p == QUOTECHAR) *lm++ = *p++;
  422.  
  423.     for (pe = ++p; *pe; pe++)
  424.         switch (*pe) {
  425.  
  426.         case '{':
  427.             brclev++;
  428.             continue;
  429.  
  430.         case '}':
  431.             if (brclev == 0)
  432.                 goto pend;
  433.             brclev--;
  434.             continue;
  435.  
  436.         case '[':
  437.             for (pe++; *pe && *pe != ']'; pe++)
  438.                 if (*p == QUOTECHAR) pe++;
  439.             if (!*pe)
  440.                 yyerror("Missing ']'");
  441.             continue;
  442.  
  443.         case QUOTECHAR:        /* skip this character */
  444.             pe++;
  445.             continue;
  446.         }
  447. pend:
  448.     if (brclev || !*pe) {
  449.         yyerror("Missing '}'");
  450.         return (0);
  451.     }
  452.     for (pl = pm = p; pm <= pe; pm++)
  453.         /* the strip code was a noop */
  454.         switch (*pm) {
  455.  
  456.         case '{':
  457.             brclev++;
  458.             continue;
  459.  
  460.         case '}':
  461.             if (brclev) {
  462.                 brclev--;
  463.                 continue;
  464.             }
  465.             goto doit;
  466.  
  467.         case ',':
  468.             if (brclev)
  469.                 continue;
  470. doit:
  471.             savec = *pm;
  472.             *pm = 0;
  473.             (void) strcpy((char *)lm, (char *)pl);
  474.             (void) strcat((char *)restbuf, (char *)pe + 1);
  475.             *pm = savec;
  476.             if (s == 0) {
  477.                 spathp = pathp;
  478.                 expsh(restbuf);
  479.                 pathp = spathp;
  480.                 *pathp = 0;
  481.             } else if (amatch((char *)s, restbuf))
  482.                 return (1);
  483.             sort();
  484.             pl = pm + 1;
  485.             continue;
  486.  
  487.         case '[':
  488.             for (pm++; *pm && *pm != ']'; pm++)
  489.                 if (*pm == QUOTECHAR) pm++;
  490.             if (!*pm)
  491.                 yyerror("Missing ']'");
  492.             continue;
  493.  
  494.         case QUOTECHAR:            /* skip one character */
  495.             pm++;
  496.             continue;
  497.         }
  498.     return (0);
  499. }
  500.  
  501. match(s, p)                    /* quote in p */
  502.     char *s, *p;
  503. {
  504.     register int c;
  505.     register char *sentp;
  506.     char sexpany = expany;
  507.  
  508.     if (*s == '.' && *p != '.')
  509.         return (0);
  510.     sentp = entp;
  511.     entp = s;
  512.     c = amatch(s, p);
  513.     entp = sentp;
  514.     expany = sexpany;
  515.     return (c);
  516. }
  517.  
  518. amatch(s, p)                    /* quote in p */
  519.     register char *s;
  520.     register u_char *p;
  521. {
  522.     register int scc;
  523.     int ok, lc;
  524.     char *spathp;
  525.     struct stat stb;
  526.     int c, cc;
  527.  
  528.     expany = 1;
  529.     for (;;) {
  530.         scc = *s++;
  531.         switch (c = *p++) {
  532.  
  533.         case '{':
  534.             return (execbrc((u_char *)p - 1, (u_char *)s - 1));
  535.  
  536.         case '[':
  537.             ok = 0;
  538.             lc = 077777;
  539.             while (cc = *p++) {
  540.                 if (cc == ']') {
  541.                     if (ok)
  542.                         break;
  543.                     return (0);
  544.                 }
  545.                 if (cc == QUOTECHAR) cc = *p++;
  546.                 if (cc == '-') {
  547.                     if (lc <= scc && scc <= (int)*p++)
  548.                         ok++;
  549.                 } else
  550.                     if (scc == (lc = cc))
  551.                         ok++;
  552.             }
  553.             if (cc == 0) {
  554.                 yyerror("Missing ']'");
  555.                 return (0);
  556.             }
  557.             continue;
  558.  
  559.         case '*':
  560.             if (!*p)
  561.                 return (1);
  562.             if (*p == '/') {
  563.                 p++;
  564.                 goto slash;
  565.             }
  566.             for (s--; *s; s++)
  567.                 if (amatch(s, p))
  568.                     return (1);
  569.             return (0);
  570.  
  571.         case CNULL:
  572.             return (scc == CNULL);
  573.  
  574.         default:
  575.             if (c != scc)
  576.                 return (0);
  577.             continue;
  578.  
  579.         case '?':
  580.             if (scc == CNULL)
  581.                 return (0);
  582.             continue;
  583.  
  584.         case '/':
  585.             if (scc)
  586.                 return (0);
  587. slash:
  588.             s = entp;
  589.             spathp = pathp;
  590.             while (*s)
  591.                 addpath(*s++);
  592.             addpath('/');
  593.             if (stat(path, &stb) == 0 && S_ISDIR(stb.st_mode))
  594.                 if (*p == CNULL) {
  595.                     if (which & E_TILDE)
  596.                         Cat((u_char *)path, 
  597.                             (u_char *)"");
  598.                     else
  599.                         Cat((u_char *)tilde, 
  600.                             (u_char *)tpathp);
  601.                 } else
  602.                     expsh(p);
  603.             pathp = spathp;
  604.             *pathp = CNULL;
  605.             return (0);
  606.         }
  607.     }
  608. }
  609.